package com.example.examsystem.security;

import com.example.examsystem.model.*;
import com.example.examsystem.repository.PermissionRepository;
import com.example.examsystem.repository.RoleRepository;
import com.example.examsystem.repository.RolePermissionRepository;
import com.example.examsystem.repository.UserRepository;
import com.example.examsystem.repository.UserRoleRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 自定义用户详情服务
 */
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
    
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final UserRoleRepository userRoleRepository;
    private final PermissionRepository permissionRepository;
    private final RolePermissionRepository rolePermissionRepository;
    private static final Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class);
    
    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("Loading user by username: {}", username);
        
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> {
                log.error("User not found: {}", username);
                return new UsernameNotFoundException("用户不存在: " + username);
            });
        
        log.info("Found user: {}, enabled: {}, locked: {}", 
            user.getUsername(), user.getEnabled(), user.getAccountLocked());
        log.info("User password hash: {}", user.getPassword().substring(0, 10) + "...");
        
        Set<Role> roles = getUserRoles(user.getId());
        Set<Permission> permissions = getUserPermissions(user.getId());
        log.info("User roles: {}", roles.stream().map(Role::getName).collect(Collectors.toSet()));
        
        UserDetails userDetails = UserPrincipal.create(user, roles, permissions);
        log.info("Created UserDetails for: {}", username);
        
        return userDetails;
    }
    
    @Transactional
    public UserDetails loadUserById(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + id));
        
        Set<Role> roles = getUserRoles(user.getId());
        Set<Permission> permissions = getUserPermissions(user.getId());
        
        return UserPrincipal.create(user, roles, permissions);
    }
    
    /**
     * 获取用户角色
     */
    private Set<Role> getUserRoles(Long userId) {
        List<UserRole> userRoles = userRoleRepository.findByUserId(userId);
        Set<Long> roleIds = userRoles.stream()
            .map(UserRole::getRoleId)
            .collect(Collectors.toSet());
        
        if (roleIds.isEmpty()) {
            return new HashSet<>();
        }
        List<Role> allById = roleRepository.findAllById(roleIds);
        return new HashSet<>(allById);
    }
    
    /**
     * 获取用户权限
     */
    private Set<Permission> getUserPermissions(Long userId) {
        Set<Role> roles = getUserRoles(userId);
        Set<Long> roleIds = roles.stream()
            .map(Role::getId)
            .collect(Collectors.toSet());
        
        if (roleIds.isEmpty()) {
            return new HashSet<>();
        }
        
        Set<Permission> permissions = new HashSet<>();
        for (Long roleId : roleIds) {
            List<RolePermission> rolePermissions = rolePermissionRepository.findByRoleId(roleId);
            Set<Long> permissionIds = rolePermissions.stream()
                .map(RolePermission::getPermissionId)
                .collect(Collectors.toSet());
            
            if (!permissionIds.isEmpty()) {
                permissions.addAll(permissionRepository.findAllById(permissionIds));
            }
        }
        
        return permissions;
    }
}

